/******************************************************************************
COPYRIGHT 2012   : ATECH
Layer            : Data Link Layer(DLL)
Source File Name : Slave_lin1_dll1.c
Group            : SoftWare Team
Author           : 
Date First Issued: 12/18/2012                                                  
******************************************************************************/
#define Slave_lin1_dll1_c

/* #include */
#include "Slave_lin1_cfg.h"
#include "Slave_lin1_syst.h"
#include "Slave_lin1_dtype.h"
#include "Slave_lin1_htype.h"
#include "Slave_lin1_appl.h"
#include "Slave_lin1_apis.h"
#include "lin1Appl.h"
#include "lin1Nwn.h"
/* replace yourself head files */
#include "derivative.h"

/* variables */
LIN1_tenPhyState  LIN1_enPhyState  = LIN1_IDLE;
LIN1_tenHeadState LIN1_enHeadState = LIN1_HEAD_SYNCH;


/*****************************************************************************/
/**
 * Function Name: void lin1_ifc_init(l_u8 baud)
 * Description: LIN SCI0/SCI1 initilzation  
 *   
 * Param:   none
 * Return:  none
 * Author:  
 *****************************************************************************/
#if(SLAVE_LIN1_CHANNEL == CHANNEL_SCI0)
    #warning "Slave LIN1 is SCI0"
    void lin1_ifc_init(l_u8 baud)
    { 
        /* 8 data, no parity, 1 stop */
        SCI0CR1 = 0x00;
        SCI0CR2 = 0x00;
        SCI0SR2 = 0x00;    
        SCI0DRL = 0x00; 
        
        /* clear status flags */
        (void)SCI0SR1; 
        (void)SCI0DRL;    
        
        /* baudrate 9600bps */
        SCI0BD = baud;  
            
        /* SCI disabled in wait mode */
        SCI0CR1_SCISWAI = 1;
          
        /* LIN break length control bit */
        SCI0SR2_BRK13 = 1; //13bit
         
        //------------------------------------------
        /* Switch to the alternative register set */ 
        SCI0SR2_AMAP = 1;
        
        /* clear control registers */
        SCI0ACR1 = 0x00;
        SCI0ACR2 = 0x00;
        
        /* Clear interrupt flags by writing 1 */
        SCI0ASR1 |= (SCI0ASR1_BKDIF_MASK | SCI0ASR1_BERRIF_MASK | SCI0ASR1_RXEDGIF_MASK);
            
        /* enable break detect interrupt */
        SCI0ACR1_BKDIE = 1; 
          
        /* enable break detect circuit */
        SCI0ACR2_BKDFE = 1;
        
        /* Switch to the normal register set */
        SCI0SR2_AMAP = 0; 
        
        //------------------------------------------     
        /* transmitter enable and receiver enable */
        SCI0CR2 |= (SCI0CR2_TE_MASK | SCI0CR2_RE_MASK);
    }
#else
    #warning "Slave LIN1 is SCI1"
    void lin1_ifc_init(l_u8 baud)
    { 
        /* 8 data, no parity, 1 stop */
        SCI1CR1 = 0x00;
        SCI1CR2 = 0x00;
        SCI1SR2 = 0x00;    
        SCI1DRL = 0x00; 
        
        /* clear status flags */
        (void)SCI1SR1; 
        (void)SCI1DRL;    
        
        /* baudrate 9600bps */
        SCI1BD = baud;  
            
        /* SCI disabled in wait mode */
        SCI1CR1_SCISWAI = 1;
          
        /* LIN break length control bit */
        SCI1SR2_BRK13 = 1; //13bit
         
        //------------------------------------------
        /* Switch to the alternative register set */ 
        SCI1SR2_AMAP = 1;
        
        /* clear control registers */
        SCI1ACR1 = 0x00;
        SCI1ACR2 = 0x00;
        
        /* Clear interrupt flags by writing 1 */
        SCI1ASR1 |= (SCI1ASR1_BKDIF_MASK | SCI1ASR1_BERRIF_MASK | SCI1ASR1_RXEDGIF_MASK);
            
        /* enable break detect interrupt */
        SCI1ACR1_BKDIE = 1; 
          
        /* enable break detect circuit */
        SCI1ACR2_BKDFE = 1;
        
        /* Switch to the normal register set */
        SCI1SR2_AMAP = 0; 
        
        //------------------------------------------     
        /* transmitter enable and receiver enable */
        SCI1CR2 |= (SCI1CR2_TE_MASK | SCI1CR2_RE_MASK);
    }
#endif

/*****************************************************************************/
/**
 * Function Name: void lin1_ifc_tx(l_u8 tmpRxData)
 * Description: send(DATAmax+CHECKSUM)  
 *   
 * Param:   none
 * Return:  whether finish sending
 * Author:  
 *****************************************************************************/
void lin1_ifc_tx(l_u8 tmpRxData)
{
    (void)tmpRxData;
    
	/* 1.first judge */
	if(LIN1_BytesToSent==LIN1_ID_Table[LIN1_CurrIdIndex].length)/* data+checksum */ 
	{	
		/* send all datas over! */
		/* the last sent byte interrupt is here */
		LIN1_ID_Table[LIN1_CurrIdIndex].transmitted_flag=L_YES;
		LIN1_enPhyState = LIN1_IDLE;
		LIN1_Rx_DISABLE();
		return;
	}

	LIN1_BytesToSent++;

	/* 2.then send */
	LIN1_UART_SEND_BUF=LIN1_Tx_Buffer[LIN1_BytesToSent];
}

/*****************************************************************************/
/**
 * Function Name: void lin1_ifc_rx(l_u8 tmpRxData)
 * Description: receive(DATAmax+CHECKSUM)  
 *   
 * Param:   none
 * Return:  whether finish receiving
 * Author:  
 *****************************************************************************/
void lin1_ifc_rx(l_u8 tmpRxData)
{
    /* 1.first receive */
    LIN1_Rx_Buffer[LIN1_BytesToReceived]=tmpRxData;
    
    LIN1_BytesToReceived++;
    
    /* 2.then judge */ 
    if(LIN1_BytesToReceived==LIN1_ID_Table[LIN1_CurrIdIndex].length+1)/* data+checksum */
    {   
        /* receive all datas over! */
        /* the last recieved byte interrupt is here */
        if(lin1_ifc_receive_message() == L_OK)
        {
            /* if checksum error,not treat as a valid message */
            LIN1_ID_Table[LIN1_CurrIdIndex].received_flag = L_YES;
            LIN1_ID_Table[LIN1_CurrIdIndex].timeout_time  = LIN1_TIMEOUT_TIME;
            LIN1_ID_Table[LIN1_CurrIdIndex].timeout_flag  = L_NO;            
        }
        LIN1_enPhyState = LIN1_IDLE;
        LIN1_Rx_DISABLE();       
    }   
}

/*****************************************************************************/
/**
 * Function Name: void lin1_ifc_rx_sleep(l_u8 tmpRxData)
 * Description: receive(DATAmax+CHECKSUM)  
 *   
 * Param:   none
 * Return:  whether finish receiving
 * Author:  
 *****************************************************************************/
void lin1_ifc_rx_sleep(l_u8 tmpRxData)
{
    /* 1.first receive */
    LIN1_Sleep_Frame_Rx_Buffer[LIN1_BytesToReceived]=tmpRxData;
    
    LIN1_BytesToReceived++;
    
    /* 2.then judge */ 
    if(LIN1_BytesToReceived==SLEEP_FRAME_LENTH+1)/* data+checksum */
    {   
        /* receive all datas over! */
        /* the last recieved byte interrupt is here */
        lin1_sys_vClearEvent(LIN1_EVENT_RecieveSleepCommand);
        lin1_ifc_goto_sleep();
        LIN1_enPhyState = LIN1_IDLE;
        LIN1_Rx_DISABLE();       
    }    
}

/*****************************************************************************/
/**
 * Function Name: l_u8 lin1_ifc_analysis_ID(l_u8 id)
 * Description:   including all master ID(no matter who it ponits to) and itself slave ID
 *   
 * Param:   none
 * Return:  
 * Author:  
 *****************************************************************************/
l_u8 lin1_ifc_analysis_ID(l_u8 id)
{   
    l_u8 i=0;                                           
    
    /* seek for available ID */
    for(i=0;i<LIN1_ID_TABLE_SIZE;i++)
    {
        if(LIN1_ID_Table[i].id==id)
        {
            LIN1_CurrIdIndex=i;
            if((id != DIAG_REQUEST_ID) && (id != DIAG_RESPONSE_ID))
            {
            	/* just for app ID */
				if((!lin1_ld_tx_raw_Enable()) && (LIN1_ID_Table[i].dir == LIN1_ID_DIRECTION_TX))
				{
					/* disable tx ID */
					return L_FAILURE;
				}
				else if((!lin1_ld_rx_raw_Enable()) && (LIN1_ID_Table[i].dir == LIN1_ID_DIRECTION_RX))
				{
					/* disable rx ID */
					return L_FAILURE;
				}
            }          
            return L_SUCCESS;        
        }
    }
    
    /* sleep command, if 0x3C not as diag request in LDF */
    if(id == SLEEP_ID)
    {
        return L_SPECIAL;    
    }

    /* invalid ID */
    return L_FAILURE; 
}

/*****************************************************************************/
/**
 * Function Name: void lin1_ifc_rx_Head(l_u8 tmpRxData)
 * Description:   receive frame head
 *   
 * Param:   none
 * Return:  
 * Author:  
 *****************************************************************************/
void lin1_ifc_rx_Head(l_u8 tmpRxData)
{     
    l_u8 u8Temp;
    
    switch(LIN1_enHeadState)
    {
       case LIN1_HEAD_SYNCH:/* 0x55 */
            if(tmpRxData!=LIN_SYNCH)
            {   /* synch error */
                LIN1_CurrIdIndex=L_ID_INDEX_NOTHING; 
                LIN1_enPhyState = LIN1_IDLE;
                LIN1_Rx_DISABLE();
            }
            else
            {
                LIN1_enHeadState=LIN1_HEAD_ID;
            }       
       break;
            
       case LIN1_HEAD_ID:/* ID */
            u8Temp = lin1_ifc_analysis_ID(tmpRxData);
            if(u8Temp==L_FAILURE)
            {   /* ID error */
                LIN1_CurrIdIndex=L_ID_INDEX_NOTHING; 
                LIN1_enPhyState = LIN1_IDLE;
                LIN1_Rx_DISABLE();    
            }
            else
            {
               lin1_sys_vSetEvent(LIN1_EVENT_RecievedFrameHead);
               if(u8Temp==L_SUCCESS)
               { 
                    if(LIN1_ID_Table[LIN1_CurrIdIndex].dir==LIN1_ID_DIRECTION_TX)
                    {
                        (void)lin1_ifc_send_message();
                        LIN1_enPhyState=LIN1_TX;
                    }
                    else
                    { 
                        LIN1_enPhyState=LIN1_RX;
                    }
                }
                else if(u8Temp==L_SPECIAL)
                {
                    lin1_sys_vSetEvent(LIN1_EVENT_RecieveSleepCommand);
                    LIN1_enPhyState=LIN1_RX;       
                }                
            }
       break;
            
       default:
       break; 
    }
}

/*****************************************************************************/
/**
 * Function Name: void lin1_ifc_isrUART(l_u8 tmpRxData)
 * Description:   
 *   
 * Param:   none
 * Return:  
 * Author:  
 *****************************************************************************/
void lin1_ifc_isrUART(l_u8 tmpRxData)
{
    switch(LIN1_enPhyState)
    {
       case LIN1_HEAD:/* frame head,including 0x55 and ID */
            lin1_ifc_rx_Head(tmpRxData);
            break;
        
       case LIN1_TX:
            lin1_ifc_tx(tmpRxData);
            break;
             
       case LIN1_RX:
            if(lin1_sys_boGetEvent(LIN1_EVENT_RecieveSleepCommand))
            {
                lin1_ifc_rx_sleep(tmpRxData);    
            }
            else
            {
                lin1_ifc_rx(tmpRxData);    
            }       
            break;
            
       case LIN1_IDLE:
            break;
             
       default:
             break;         
    }
}

/*****************************************************************************/
/**
 * Function Name: @interrupt void lin1_ifc_isrEXTI(void)
 * Description: when Rx Pin recieve (250us~5ms low level),
 *              trigger this external interrupt  
 *   
 * Param:   none
 * Return:  none
 * Author:  
 *****************************************************************************/
void lin1_ifc_isrEXTI(void)
{
#ifdef LIN1_REMOTE_WAKEUP_ITSELF
    /* wakeup LIN sleep mode */
    lin1_sys_vSetEvent(LIN1_EVENT_RecievedRemoteWakeUp);
    /* wakeup system lowpower mode */
    lin1_hook_vEXTI();
#endif
}

/*****************************************************************************/
/**
* Function Name: __interrupt void Comm_isr_SCI0(void)
 * Description: SCI/UART interrupt function   
 * we only use receive interrupt because transmit complete interrupt is
 * invoked before receive interrupt. If we enable RX interrupt once we
 * transmitted the last byte we might get a received interrupt straight
 * away   
 * Param:   none
 * Return:  none
 * Author:  
 *****************************************************************************/
#pragma CODE_SEG __NEAR_SEG NON_BANKED

#if(SLAVE_LIN1_CHANNEL == CHANNEL_SCI0)
    __interrupt void Comm_isr_SCI0(void)
    {   
        l_u8 tmpSR1;
        l_u8 tmpRxData;  
        
        SCI0SR2_AMAP = 1;
        if(SCI0ACR1_RXEDGIE)
        {
            if(SCI0ASR1_RXEDGIF) 
            {
                SCI0ASR1_RXEDGIF = 1;/* clear this flag by writing 1 */
                SCI0SR2_AMAP = 0;
                lin1_hook_vBusActivity();        
                lin1_ifc_isrEXTI();
                return;    
            }      
        }
        SCI0SR2_AMAP = 0;
        
        SCI0SR2_AMAP = 1;
        if(SCI0ASR1 & SCI0ASR1_BKDIF_MASK)/* break interrupt */
        {
            SCI0ASR1|=SCI0ASR1_BKDIF_MASK;/* clear interrupt flag by writing 1 */
            SCI0SR2_AMAP = 0;
            (void)SCI0SR1;
            (void)SCI0DRL;
            lin1_hook_vBusActivity();
            (void)lin1_ifc_break_action();
            LIN1_enPhyState=LIN1_HEAD;
            LIN1_enHeadState=LIN1_HEAD_SYNCH;
            LIN1_Rx_ENABLE();
            return;
        }
        SCI0SR2_AMAP = 0;
           
        if(!(SCI0CR2 & SCI0CR2_RIE_MASK))/* Rx interrupt */ 
        {
           (void)SCI0SR1;
           (void)SCI0DRL;
           return;
        }
        
        //-----------------------------------------
        tmpSR1=SCI0SR1;
        if(tmpSR1 & SCI0SR1_OR_MASK)
        {
           (void)SCI0SR1;
           (void)SCI0DRL;
           return;
        }
        else if(tmpSR1 & SCI0SR1_RDRF_MASK)
        {
            if(tmpSR1 & (SCI0SR1_PF_MASK | SCI0SR1_FE_MASK | SCI0SR1_OR_MASK))
            {
               (void)SCI0SR1;
               (void)SCI0DRL;
               return;
            }
            (void)SCI0SR1;
            lin1_hook_vBusActivity();
            tmpRxData = LIN1_UART_RECEIVE_BUF;
            lin1_ifc_isrUART(tmpRxData);
        }
    }
#else
    __interrupt void Comm_isr_SCI1(void)
    {   
        l_u8 tmpSR1;
        l_u8 tmpRxData;  
        
        SCI1SR2_AMAP = 1;
        if(SCI1ACR1_RXEDGIE)
        {
            if(SCI1ASR1_RXEDGIF) 
            {
                SCI1ASR1_RXEDGIF = 1;/* clear this flag by writing 1 */
                SCI1SR2_AMAP = 0;
                lin1_hook_vBusActivity();        
                lin1_ifc_isrEXTI();
                return;    
            }      
        }
        SCI1SR2_AMAP = 0;
        
        SCI1SR2_AMAP = 1;
        if(SCI1ASR1 & SCI1ASR1_BKDIF_MASK)/* break interrupt */
        {
            SCI1ASR1|=SCI1ASR1_BKDIF_MASK;/* clear interrupt flag by writing 1 */
            SCI1SR2_AMAP = 0;
            (void)SCI1SR1;
            (void)SCI1DRL;
            lin1_hook_vBusActivity();
            (void)lin1_ifc_break_action();
            LIN1_enPhyState=LIN1_HEAD;
            LIN1_enHeadState=LIN1_HEAD_SYNCH;
            LIN1_Rx_ENABLE();
            return;
        }
        SCI1SR2_AMAP = 0;
           
        if(!(SCI1CR2 & SCI1CR2_RIE_MASK))/* Rx interrupt */ 
        {
           (void)SCI1SR1;
           (void)SCI1DRL;
           return;
        }
        
        //-----------------------------------------
        tmpSR1=SCI1SR1;
        if(tmpSR1 & SCI1SR1_OR_MASK)
        {
           (void)SCI1SR1;
           (void)SCI1DRL;
           return;
        }
        else if(tmpSR1 & SCI1SR1_RDRF_MASK)
        {
            if(tmpSR1 & (SCI1SR1_PF_MASK | SCI1SR1_FE_MASK | SCI1SR1_OR_MASK))
            {
               (void)SCI1SR1;
               (void)SCI1DRL;
               return;
            }
            (void)SCI1SR1;
            lin1_hook_vBusActivity();
            tmpRxData = LIN1_UART_RECEIVE_BUF;
            lin1_ifc_isrUART(tmpRxData);
        }
    }
#endif

#pragma CODE_SEG DEFAULT


 /*****************************************************************************/
/**
 * Function Name: void lin1_ifc_UART_switchTo_EXTI(void)
 * Description: switch UART to EXTI  
 *   
 * Param:   none
 * Return:  none
 * Author:  
 *****************************************************************************/
#if(SLAVE_LIN1_CHANNEL == CHANNEL_SCI0)
    void lin1_ifc_UART_switchTo_EXTI(void)
    {   
        /* PS0: I  LIN_IN,external interrupt enable */  
     SCI0SR2_AMAP = 1;
        SCI0ASR1_RXEDGIF = 1;/* must clear this flag by writing 1 here */
        SCI0ACR1_RXEDGIE = 1;
     SCI0SR2_AMAP = 0;
    }
#else
    void lin1_ifc_UART_switchTo_EXTI(void)
    {   
        /* PS0: I  LIN_IN,external interrupt enable */  
     SCI1SR2_AMAP = 1;
        SCI1ASR1_RXEDGIF = 1;/* must clear this flag by writing 1 here */
        SCI1ACR1_RXEDGIE = 1;
     SCI1SR2_AMAP = 0;
    }
#endif

 /*****************************************************************************/
/**
 * Function Name: void lin1_ifc_EXTI_switchTo_UART(void)
 * Description: switch EXTI to UART   
 *   
 * Param:   none
 * Return:  none
 * Author:  
 *****************************************************************************/
#if(SLAVE_LIN1_CHANNEL == CHANNEL_SCI0)
    void lin1_ifc_EXTI_switchTo_UART(void)
    {
        /* PS0: I  LIN_IN,external interrupt disable */
     SCI0SR2_AMAP = 1;   
        SCI0ACR1_RXEDGIE = 0;
     SCI0SR2_AMAP = 0;
    } 
#else
    void lin1_ifc_EXTI_switchTo_UART(void)
    {
        /* PS0: I  LIN_IN,external interrupt disable */
     SCI1SR2_AMAP = 1;   
        SCI1ACR1_RXEDGIE = 0;
     SCI1SR2_AMAP = 0;
    } 
#endif


